package com.hopedove.workshop.viewmodel

import androidx.databinding.Observable
import androidx.databinding.ObservableField
import androidx.databinding.ObservableInt
import androidx.lifecycle.LiveData
import androidx.lifecycle.viewModelScope
import com.hadilq.liveevent.LiveEvent
import com.hopedove.net.ApiCallResult
import com.hopedove.viewmodel.BaseViewModel
import com.hopedove.workshop.api.MaterialItem
import com.hopedove.workshop.api.RunningSituationAdd
import com.hopedove.workshop.api.RunningSituationType
import com.hopedove.workshop.api.WorkshopApi
import com.hopedove.workshop.data.pojo.ObservableRecordItem
import com.hopedove.workshop.repository.WorkshopUserRepository
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch

class WorkshopRunningSituationRecordViewModel(
    private val api: WorkshopApi,
    private val userRepository: WorkshopUserRepository,
) : BaseViewModel() {

    private val _types = LiveEvent<List<RunningSituationType>>()
    val types: LiveData<List<RunningSituationType>> = _types

    // 记录原料列表（当客户选中【原料】类型后）
    private val _materials = LiveEvent<List<MaterialItem>>()
    val materials: LiveData<List<MaterialItem>> = _materials

    // 记录总的条目
    private val _recordItems = LiveEvent<List<ObservableRecordItem>>()
    val recordItems: LiveData<List<ObservableRecordItem>> = _recordItems

    var displayName = ObservableField<String>()

    // 记录选中的类型
    val selectedType = ObservableInt(-1)
    val machineNo = ObservableField<String>()

    private var saveListJob: Job? = null
    private var addTypeJob: Job? = null

    // 记录【计划类型】列表
    private var planTypes: List<RunningSituationType>? = null

    override fun load() = viewModelScope.launch {

        val result = api.runningSituationGetTypes()
        when (result) {
            is ApiCallResult.Success -> {
                _types.value = result.data!!
            }
            is ApiCallResult.Error -> _toastText.value = result.error
        }

        when (val planTypeResult = api.getPlanTypeList()) {
            is ApiCallResult.Success -> {
                planTypes = planTypeResult.data
            }
            is ApiCallResult.Error -> _toastText.value = planTypeResult.error
        }

        displayName.set("记录人：${userRepository.getSignedInUserName()}")

        selectedType.addOnPropertyChangedCallback(object : Observable.OnPropertyChangedCallback() {
            override fun onPropertyChanged(sender: Observable?, propertyId: Int) {
                clearMachineAndList()
            }
        })


    }

    /**
     *  当选中的原料列表确认时的回调
     */
    fun onMaterialListItemSelected(indexes: List<Int>) {
        if (!checkStates()) return
        val type = types.value!![selectedType.get()]
        val machine = machineNo.get()!!
        setRecordList(type, machine, indexes)
    }

    /**
     *  输入完车号后，ActionDone 的回调，表示添加一条记录
     */
    fun onAddRecords() {
        if (!checkStates()) return
        if (addTypeJob != null) return

        val type = types.value!![selectedType.get()]
        val machine = machineNo.get()!!

        addTypeJob = viewModelScope.launch {
            when (val result = api.validateMachineNo(machine)) {
                is ApiCallResult.Success -> {
                    if (isMaterialType(type)) {
                        // 如果是【原料】或 【布料】类型，则请求原料列表，让用户选择
                        requestMaterialList(machine)
                    } else {
                        setRecordList(type, machine)
                    }
                }
                is ApiCallResult.Error -> {
                    _toastText.value = result.error
                }
            }
        }.apply { invokeOnCompletion { addTypeJob = null } }

    }

    /**
     *  保存
     */
    fun save() {
        saveRecordList()
    }

    /**
     *  保存列表
     */
    private fun saveRecordList() {
        // 检测【待上传列表】是否为空
        if (recordItems.value?.isEmpty() == true || recordItems.value == null) {
            _toastText.value = "列表为空"
            return
        }

        // 检查是否有条目 3 项同时为空
        recordItems.value!!.forEachIndexed { index, item ->
            if (item.allObservableFieldIsEmpty()) {
                _toastText.value = "第 ${index + 1} 条的三项不能全为空"
                return
            }
        }

        // 检查【计划类型】列表是否为空
        val planTypeList = if (planTypes != null) planTypes!! else {
            _toastText.value = "计划类型列表为空"
            return
        }


        if (saveListJob?.isCompleted?.not() == true) return

        val userSession = userRepository.getSignedUserSession() ?: return

        // 转换数据格式为符合 API 调用的要求
        val list = recordItems.value?.let { records ->
            records.map { item ->
                //
                val planTypeIndex = item.planTypeSelection.get()
                val planTypeCode = if (planTypeIndex < 0) "" else planTypeList[planTypeIndex].code

                RunningSituationAdd(
                    item.type,
                    item.machine,
                    item.remark.get() ?: "",
                    item.reason.get() ?: "",
                    item.duration.get() ?: "",
                    item.groupNo,
                    item.id,
                    item.index,
                    planTypeCode
                )
            }
        } ?: return

        _loading.value = true
        saveListJob = viewModelScope.launch {

            val result = api.runningSitationAdd(
                userSession.userId,
                userSession.userName,
                list = list
            )

            when (result) {
                is ApiCallResult.Success -> {
                    _toastText.value = "保存成功"
                    clearMachineAndList()
                }
                is ApiCallResult.Error -> _toastText.value = result.error
            }

            _loading.value = false
        }
    }

    private suspend fun requestMaterialList(machineNo: String) {
        _loading.value = true

        when (val result = api.runningSituationGetMaterials(machineNo)) {
            is ApiCallResult.Success -> {
                if (result.data!!.isNotEmpty()) {
                    _materials.value = result.data!!
                } else {
                    _toastText.value = "原料列表为空"
                }
            }
            is ApiCallResult.Error -> _toastText.value = result.error
        }

        _loading.value = false
    }


    /**
     *
     * @param append 是否在原有的列表中添加，如果是 false，之前的列表内容会清空
     */
    private fun setRecordList(
        type: RunningSituationType,
        machineNo: String,
        materials: List<Int>? = null,
        append: Boolean = false
    ) {

        //  根据选中的 id 来确认类型
        val list = mutableListOf<ObservableRecordItem>().apply {
            val emptyList = mutableListOf<ObservableRecordItem>()
            addAll(if (append) _recordItems.value ?: emptyList else emptyList)
        }

        // 判断【计划类型】列表是否加载成功
        val planTypeList = if (planTypes != null) planTypes!! else {
            _toastText.value = "计划类型列表为空"
            return
        }

        if (isMaterialType(type) && materials != null) {
            materials.forEach { index ->
                val m = _materials.value!![index]
                val item = ObservableRecordItem(
                    type.code,
                    machineNo,
                    remark = ObservableField(m.name),
                    reason = ObservableField(""),
                    duration = ObservableField(""),
                    groupNo = m.groupNo,
                    id = m.id,
                    index = m.index ?: "",
                    planTypes = planTypeList.map { it.name }
                )
                list.add(item)
            }
            _recordItems.value = list
        } else {
            list.add(
                ObservableRecordItem(
                    type.code,
                    machineNo,
                    planTypes = planTypeList.map { it.name })
            )
            _recordItems.value = list
        }

    }


    private fun checkStates(): Boolean {
        // 判断是否有选中类型
        if (selectedType.get() < 0) {
            _toastText.value = "请选择类型"
            return false
        }

        if (types.value == null) {
            _toastText.value = "类型不能为空"
            return false
        }

        if (planTypes == null) {
            _toastText.value = "计划类型为空"
            return false
        }

        if (machineNo.get().isNullOrEmpty()) {
            _toastText.value = "车号不能为空"
            return false
        }

        return true
    }

    private fun clearMachineAndList() {
        machineNo.set("")
        _recordItems.value = emptyList()
    }

    private fun isMaterialType(type: RunningSituationType) = type.name == "原料" || type.name == "布票"

}